#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "md5.h"
#include "sha.h"
#include "bloom.h"

/*$Id: bloom.c 5 2012-10-26 04:17:18Z hymm91@gmail.com $*/
/*计算bloom hash值 36位，9轮*/
static void calchash(const char *str, int strlen, char *out);



void calchash(const char *str, int strlen, char *out)
{
	struct md5_context md5_ctx;
	md5_starts(&md5_ctx);
	md5_update(&md5_ctx,  (uint8 *)str, (uint32)strlen);
	md5_finish(&md5_ctx,  (unsigned char *)out);
	j_SHA_CTX sha_ctx;
	shaInit(&sha_ctx);
	shaUpdate(&sha_ctx, (unsigned char *)str, strlen);
	shaFinal(&sha_ctx, (unsigned char *)(out + 16));
}


/***********************************************************
 * 名称: bloom_starts
 * 作用: bloom 数据初始及载入
 * 参数: 
 *     file: 保存bloom数据文件
 *     init: 是否首次初始
 *     size: bloom 判重数据大小
 *     返回值: = 0 成功 -1  file 文件大小与size 不符
 *     >0 errno
 *     ctx 保存bloom 上下文
 *     创建日期: 2009-02-02
 *     修改日期: 无
 *     作者: robble
 *     ************************************************************/
int bloom_starts(const char *file, int init,  ssize_t size, struct bloom_context *ctx)
{
	struct stat st;
	FILE *fp;
	ssize_t fsize = 0;

	//未传入文件名
	if ((file == NULL || file[0] == '\0')) 
		init = 1;

		
	if ((stat(file, &st)) == -1) {
		//文件不存在 且传入了文件名 	
		if (errno == ENOENT && file && file[0] != '\0') {
			fp = fopen(file, "w+b");
			if (NULL == fp) {
				return errno;
			}	
			fclose(fp);
			fsize = 0;
		}  // end if (errno == ENOENT
	} else { 
		fsize = st.st_size;
	}

	ctx->size = ((int)((size + 7) >> 3)) << 3;

	if (NULL != file && file[0] != '\0') { 
		//是否有读写权限
		if ((access(file, W_OK | R_OK)) != 0) {
			return errno;
		} 
		if (fsize != 0 && fsize != (ctx->size >> 3)) {
			return -1;
		}
	}
	ctx->dat = (unsigned char *)malloc(ctx->size >> 3);
	if (NULL == ctx->dat) {
		return errno;
	}
	memset(ctx->dat, 0, ctx->size >> 3);
	if (init == 0 && fsize > 0) { 
		fp = fopen(file, "r+");
		if (NULL == fp) {
			return errno;	
		}
		fsize = fread(ctx->dat, 1, ctx->size >> 3, fp);
		if (fsize < (ctx->size >> 3)) {
			fclose(fp);
			return errno;
		}
		fclose(fp);
	}
	if (NULL != file || file[0] != '\0') {
		ctx->file = strdup(file);
	} else {
		ctx->file = NULL;
	} 
	return 0;
}

static unsigned char _bitmod[] = {1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7};

int bloom_isexist(const char *str, int strlen, struct bloom_context * ctx)
{
	unsigned int  hash[9];
	unsigned int bitnum;
	register int pos;
	register int i;
	unsigned char mod_val;
	int k = 0;

	calchash(str, strlen, (char *)hash);

	for (i = 0; i < 9; i ++) {
		bitnum = hash[i] % ctx->size;
		pos = bitnum >> 3;
		mod_val = _bitmod[bitnum & 7];
		if ((ctx->dat[pos] & mod_val) == 0) {
			ctx->dat[pos]  |=  mod_val;
			k ++;
		}
	}
	return k == 0;
}

int bloom_finish(struct bloom_context *ctx)
{
	FILE *fp;
	ssize_t n;
	if (NULL != ctx->file && ctx->file[0] != '\0') {
		fp = fopen(ctx->file, "w+b");
		if (NULL == fp)
			return errno;
		n = fwrite(ctx->dat, 1, ctx->size >> 3, fp);
		if (n < ctx->size >> 3) {
			fclose(fp);
			return errno;
		}
		fclose(fp);
	}
	return 0;
}





/*$Id: bloom.c 5 2012-10-26 04:17:18Z hymm91@gmail.com $*/
